﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Unity.InterceptionExtension;
using Microsoft.VisualStudio.TestTools.UnitTesting;


namespace ParallelCacheHandler.UnitTest
{
    [TestClass]
    public class CacheKeyGenerationTest
    {
        [TestMethod]
        public void CacheableMethodWithoutParams()
        {
            int param1 = 77;
            string param2 = "sfsdf";
            long param3 = 666;
            double param4 = 99.0d;

            var methodBase = this.GetType().GetMethod("dummyMethod");

            var invocation = new VirtualMethodInvocation(this, methodBase, new object[] { param1, param2, param3, param4 });

            var key = CacheKeyGenerator.GetCacheKey(invocation);

            Assert.AreEqual("Void dummyMethod()", key);

        }

        [TestMethod]
        public void CacheableMethodWithParams()
        {
            int param1 = 77;
            long param2 = 666;
            double param3 = 99.0d;

            var methodBase = this.GetType().GetMethod("dummyMethodWithParams");

            var invocation = new VirtualMethodInvocation(this, methodBase, new object[] { param1, param2, param3 });

            var key = CacheKeyGenerator.GetCacheKey(invocation);

            Assert.AreEqual("Void dummyMethodWithParams(Int32, Int64, Double)|77||666||1079558144|", key);

        }

        [TestMethod]
        [ExpectedException(typeof(CacheKeyException))]
        public void NonCacheableMethod()
        {
            int param1 = 77;
            var param2 = new NonEqutableShim();

            var methodBase = this.GetType().GetMethod("dummyMethodWithComplexParams");

            var invocation = new VirtualMethodInvocation(this, methodBase, new object[] { param1, param2 });

            var key = CacheKeyGenerator.GetCacheKey(invocation);

        }

        [TestMethod]
        public void CacheableMethodWithEquatableInput()
        {
            int param1 = 77;
            var param2 = new EquitableShim("Rocks", 78);
            var param3 = new EquitableShim("Rocks", 78);
            var param4 = new EquitableShim("rocks", 78);
            int param5 = 44;

            var methodBase = this.GetType().GetMethod("dummyMethodWithEquitableParams");

            var invocation1 = new VirtualMethodInvocation(this, methodBase, new object[] { param1, param2 });
            var key1 = CacheKeyGenerator.GetCacheKey(invocation1);

            var invocation2 = new VirtualMethodInvocation(this, methodBase, new object[] { param1, param3 });
            var key2 = CacheKeyGenerator.GetCacheKey(invocation2);

            var invocation3 = new VirtualMethodInvocation(this, methodBase, new object[] { param1, param4 });
            var key3 = CacheKeyGenerator.GetCacheKey(invocation3);

            var invocation4 = new VirtualMethodInvocation(this, methodBase, new object[] { param5, param2 });
            var key4 = CacheKeyGenerator.GetCacheKey(invocation3);

            Assert.AreEqual(key1, key2);

            Assert.AreNotEqual(key1, key3);

            Assert.AreNotEqual(key1, key4);

        }

        public class EquitableShim : IEquatable<EquitableShim>
        {
            string _uniqueName;
            int _uniqueId;

            public EquitableShim(string uniqueName, int uniqueId)
            {
                _uniqueId = uniqueId;
                _uniqueName = uniqueName;
            }


            public bool Equals(EquitableShim other)
            {
                return (String.Compare(_uniqueName, other._uniqueName) == 0 && _uniqueId == other._uniqueId);
            }

            public override int GetHashCode()
            {
                unchecked // Overflow is fine, just wrap
                {
                    int hash = 17;
                    // Suitable nullity checks etc, of course :)
                    hash = hash * 23 + _uniqueName.GetHashCode();
                    hash = hash * 23 + _uniqueId.GetHashCode();
                    return hash;
                }
            }
        }

        public class NonEqutableShim
        {

        }

        public void dummyMethod()
        {
        }

        public void dummyMethodWithParams(int i, long j, double k)
        {
        }

        public void dummyMethodWithComplexParams(int i, NonEqutableShim shim)
        {
        }

        public void dummyMethodWithEquitableParams(int i, EquitableShim shim)
        {
        }
    }
}
